#include "wal_manager.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <inttypes.h>
#include <zlib.h>  // For CRC32

// Internal constants
#define WAL_MAGIC_NUMBER    0x57414C21  // "WAL!"
#define WAL_VERSION         1
#define WAL_SEGMENT_PREFIX  "wal_"
#define WAL_CHECKPOINT_FILE "checkpoint.dat"

// Static function declarations
static lsn_t assign_lsn(wal_manager_t* wal);
static int write_record_to_buffer(wal_manager_t* wal, wal_record_t* record);
static int create_wal_directory(const char* path);
static char* get_segment_filename(const char* wal_dir, uint32_t segment_id);
static int write_segment_header(wal_segment_t* segment);
static int read_segment_header(wal_segment_t* segment);

// WAL Manager lifecycle
wal_manager_t* wal_manager_create(const char* wal_directory) {
    if (!wal_directory) {
        return NULL;
    }
    
    wal_manager_t* wal = malloc(sizeof(wal_manager_t));
    if (!wal) {
        return NULL;
    }
    
    memset(wal, 0, sizeof(wal_manager_t));
    
    // Copy directory path
    wal->wal_directory = malloc(strlen(wal_directory) + 1);
    if (!wal->wal_directory) {
        free(wal);
        return NULL;
    }
    strcpy(wal->wal_directory, wal_directory);
    
    // Set default configuration
    wal->segment_size = WAL_SEGMENT_SIZE;
    wal->buffer_size = WAL_BUFFER_SIZE;
    wal->sync_interval_ms = WAL_SYNC_INTERVAL;
    wal->checkpoint_interval_sec = WAL_CHECKPOINT_INTERVAL;
    
    // Initialize LSN management
    wal->next_lsn = BOOTSTRAP_LSN;
    wal->flushed_lsn = INVALID_LSN;
    wal->checkpoint_lsn = INVALID_LSN;
    
    if (pthread_mutex_init(&wal->lsn_mutex, NULL) != 0) {
        free(wal->wal_directory);
        free(wal);
        return NULL;
    }
    
    // Initialize segments lock
    if (pthread_rwlock_init(&wal->segments_lock, NULL) != 0) {
        pthread_mutex_destroy(&wal->lsn_mutex);
        free(wal->wal_directory);
        free(wal);
        return NULL;
    }
    
    // Initialize flush synchronization
    if (pthread_mutex_init(&wal->flush_mutex, NULL) != 0 ||
        pthread_cond_init(&wal->flush_cond, NULL) != 0) {
        pthread_rwlock_destroy(&wal->segments_lock);
        pthread_mutex_destroy(&wal->lsn_mutex);
        free(wal->wal_directory);
        free(wal);
        return NULL;
    }
    
    // Create WAL buffer
    wal->buffer = wal_buffer_create(wal->buffer_size);
    if (!wal->buffer) {
        pthread_cond_destroy(&wal->flush_cond);
        pthread_mutex_destroy(&wal->flush_mutex);
        pthread_rwlock_destroy(&wal->segments_lock);
        pthread_mutex_destroy(&wal->lsn_mutex);
        free(wal->wal_directory);
        free(wal);
        return NULL;
    }
    
    // Create WAL directory if it doesn't exist
    if (create_wal_directory(wal_directory) != 0) {
        wal_buffer_destroy(wal->buffer);
        pthread_cond_destroy(&wal->flush_cond);
        pthread_mutex_destroy(&wal->flush_mutex);
        pthread_rwlock_destroy(&wal->segments_lock);
        pthread_mutex_destroy(&wal->lsn_mutex);
        free(wal->wal_directory);
        free(wal);
        return NULL;
    }
    
    return wal;
}

void wal_manager_destroy(wal_manager_t* wal) {
    if (!wal) return;
    
    // Stop background threads
    wal_manager_stop(wal);
    
    // Close all segments
    pthread_rwlock_wrlock(&wal->segments_lock);
    wal_segment_t* segment = wal->segments;
    while (segment) {
        wal_segment_t* next = segment->next;
        wal_close_segment(wal, segment);
        segment = next;
    }
    pthread_rwlock_unlock(&wal->segments_lock);
    
    // Destroy buffer
    wal_buffer_destroy(wal->buffer);
    
    // Destroy synchronization objects
    pthread_cond_destroy(&wal->flush_cond);
    pthread_mutex_destroy(&wal->flush_mutex);
    pthread_rwlock_destroy(&wal->segments_lock);
    pthread_mutex_destroy(&wal->lsn_mutex);
    
    // Free checkpoint info
    if (wal->last_checkpoint) {
        free(wal->last_checkpoint->checkpoint_filename);
        free(wal->last_checkpoint);
    }
    
    free(wal->wal_directory);
    free(wal);
}

int wal_manager_start(wal_manager_t* wal) {
    if (!wal) return -1;
    
    // Create initial segment
    wal->active_segment = wal_create_segment(wal);
    if (!wal->active_segment) {
        return -1;
    }
    
    // Start background threads
    wal->threads_running = true;
    
    if (pthread_create(&wal->writer_thread, NULL, wal_writer_thread_func, wal) != 0) {
        wal->threads_running = false;
        return -1;
    }
    
    if (pthread_create(&wal->checkpoint_thread, NULL, wal_checkpoint_thread_func, wal) != 0) {
        wal->threads_running = false;
        pthread_cancel(wal->writer_thread);
        pthread_join(wal->writer_thread, NULL);
        return -1;
    }
    
    return 0;
}

int wal_manager_stop(wal_manager_t* wal) {
    if (!wal || !wal->threads_running) return 0;
    
    // Signal threads to stop
    wal->threads_running = false;
    
    // Wake up threads
    pthread_cond_broadcast(&wal->buffer->not_empty);
    pthread_cond_broadcast(&wal->flush_cond);
    
    // Wait for threads to finish
    pthread_join(wal->writer_thread, NULL);
    pthread_join(wal->checkpoint_thread, NULL);
    
    // Final flush
    wal_force_sync(wal);
    
    return 0;
}

// Record operations
lsn_t wal_insert_record(wal_manager_t* wal, wal_record_type_t type, 
                       txn_id_t xid, const void* data, uint32_t data_size) {
    if (!wal || data_size > WAL_MAX_RECORD_SIZE) {
        return INVALID_LSN;
    }
    
    // Create WAL record
    wal_record_t* record = wal_record_create(type, xid, data, data_size);
    if (!record) {
        return INVALID_LSN;
    }
    
    // Assign LSN
    record->header.lsn = assign_lsn(wal);
    record->header.timestamp = (timestamp_t)time(NULL);
    
    // Calculate checksum
    uint32_t header_crc = wal_calculate_crc32(&record->header, 
                                            sizeof(wal_record_header_t) - sizeof(uint32_t));
    uint32_t data_crc = data_size > 0 ? wal_calculate_crc32(data, data_size) : 0;
    record->header.crc32 = header_crc ^ data_crc;
    
    // Write to buffer
    if (write_record_to_buffer(wal, record) != 0) {
        wal_record_destroy(record);
        return INVALID_LSN;
    }
    
    lsn_t lsn = record->header.lsn;
    wal_record_destroy(record);
    
    // Update statistics
    __atomic_fetch_add(&wal->records_written, 1, __ATOMIC_SEQ_CST);
    __atomic_fetch_add(&wal->bytes_written, 
                      sizeof(wal_record_header_t) + data_size, __ATOMIC_SEQ_CST);
    
    return lsn;
}

lsn_t wal_log_insert(wal_manager_t* wal, txn_id_t xid, uint32_t table_id,
                     uint32_t page_id, uint64_t tuple_id, 
                     const void* tuple_data, uint32_t data_size) {
    if (!wal || !tuple_data) return INVALID_LSN;
    
    // Create table operation data
    uint32_t total_size = sizeof(wal_table_op_data_t) + data_size;
    char* op_data = malloc(total_size);
    if (!op_data) return INVALID_LSN;
    
    wal_table_op_data_t* table_op = (wal_table_op_data_t*)op_data;
    table_op->table_id = table_id;
    table_op->page_id = page_id;
    table_op->tuple_id = tuple_id;
    table_op->old_data_size = 0;
    table_op->new_data_size = data_size;
    
    // Copy new tuple data
    memcpy(op_data + sizeof(wal_table_op_data_t), tuple_data, data_size);
    
    lsn_t lsn = wal_insert_record(wal, WAL_INSERT, xid, op_data, total_size);
    free(op_data);
    
    return lsn;
}

lsn_t wal_log_update(wal_manager_t* wal, txn_id_t xid, uint32_t table_id,
                     uint32_t page_id, uint64_t tuple_id,
                     const void* old_data, uint32_t old_size,
                     const void* new_data, uint32_t new_size) {
    if (!wal || !old_data || !new_data) return INVALID_LSN;
    
    // Create table operation data
    uint32_t total_size = sizeof(wal_table_op_data_t) + old_size + new_size;
    char* op_data = malloc(total_size);
    if (!op_data) return INVALID_LSN;
    
    wal_table_op_data_t* table_op = (wal_table_op_data_t*)op_data;
    table_op->table_id = table_id;
    table_op->page_id = page_id;
    table_op->tuple_id = tuple_id;
    table_op->old_data_size = old_size;
    table_op->new_data_size = new_size;
    
    // Copy old and new tuple data
    char* data_ptr = op_data + sizeof(wal_table_op_data_t);
    memcpy(data_ptr, old_data, old_size);
    memcpy(data_ptr + old_size, new_data, new_size);
    
    lsn_t lsn = wal_insert_record(wal, WAL_UPDATE, xid, op_data, total_size);
    free(op_data);
    
    return lsn;
}

lsn_t wal_log_delete(wal_manager_t* wal, txn_id_t xid, uint32_t table_id,
                     uint32_t page_id, uint64_t tuple_id,
                     const void* tuple_data, uint32_t data_size) {
    if (!wal || !tuple_data) return INVALID_LSN;
    
    // Create table operation data
    uint32_t total_size = sizeof(wal_table_op_data_t) + data_size;
    char* op_data = malloc(total_size);
    if (!op_data) return INVALID_LSN;
    
    wal_table_op_data_t* table_op = (wal_table_op_data_t*)op_data;
    table_op->table_id = table_id;
    table_op->page_id = page_id;
    table_op->tuple_id = tuple_id;
    table_op->old_data_size = data_size;
    table_op->new_data_size = 0;
    
    // Copy old tuple data
    memcpy(op_data + sizeof(wal_table_op_data_t), tuple_data, data_size);
    
    lsn_t lsn = wal_insert_record(wal, WAL_DELETE, xid, op_data, total_size);
    free(op_data);
    
    return lsn;
}

lsn_t wal_log_transaction_begin(wal_manager_t* wal, txn_id_t xid, 
                               isolation_level_t isolation) {
    if (!wal) return INVALID_LSN;
    
    wal_txn_op_data_t txn_data;
    txn_data.xid = xid;
    txn_data.isolation = isolation;
    txn_data.start_time = (timestamp_t)time(NULL);
    
    return wal_insert_record(wal, WAL_TRANSACTION_BEGIN, xid, 
                           &txn_data, sizeof(txn_data));
}

lsn_t wal_log_transaction_commit(wal_manager_t* wal, txn_id_t xid) {
    if (!wal) return INVALID_LSN;
    
    wal_txn_op_data_t txn_data;
    txn_data.xid = xid;
    txn_data.isolation = ISOLATION_READ_COMMITTED;  // Not used for commit
    txn_data.start_time = (timestamp_t)time(NULL);
    
    return wal_insert_record(wal, WAL_TRANSACTION_COMMIT, xid, 
                           &txn_data, sizeof(txn_data));
}

lsn_t wal_log_transaction_abort(wal_manager_t* wal, txn_id_t xid) {
    if (!wal) return INVALID_LSN;
    
    wal_txn_op_data_t txn_data;
    txn_data.xid = xid;
    txn_data.isolation = ISOLATION_READ_COMMITTED;  // Not used for abort
    txn_data.start_time = (timestamp_t)time(NULL);
    
    return wal_insert_record(wal, WAL_TRANSACTION_ABORT, xid, 
                           &txn_data, sizeof(txn_data));
}

// Flush and sync operations
int wal_flush_to_lsn(wal_manager_t* wal, lsn_t lsn) {
    if (!wal) return -1;
    
    pthread_mutex_lock(&wal->flush_mutex);
    
    // Check if already flushed
    if (lsn <= wal->flushed_lsn) {
        pthread_mutex_unlock(&wal->flush_mutex);
        return 0;
    }
    
    // Request flush
    pthread_mutex_lock(&wal->buffer->mutex);
    wal->buffer->flush_requested = true;
    wal->buffer->flush_lsn = lsn;
    pthread_cond_signal(&wal->buffer->not_empty);
    pthread_mutex_unlock(&wal->buffer->mutex);
    
    // Wait for flush to complete
    while (lsn > wal->flushed_lsn) {
        pthread_cond_wait(&wal->flush_cond, &wal->flush_mutex);
    }
    
    pthread_mutex_unlock(&wal->flush_mutex);
    return 0;
}

int wal_sync_to_lsn(wal_manager_t* wal, lsn_t lsn) {
    if (!wal) return -1;
    
    // First flush to LSN
    if (wal_flush_to_lsn(wal, lsn) != 0) {
        return -1;
    }
    
    // Then sync active segment
    if (wal->active_segment && wal->active_segment->fd >= 0) {
        if (fsync(wal->active_segment->fd) != 0) {
            return -1;
        }
        wal->active_segment->needs_sync = false;
        __atomic_fetch_add(&wal->syncs_performed, 1, __ATOMIC_SEQ_CST);
    }
    
    return 0;
}

int wal_force_sync(wal_manager_t* wal) {
    if (!wal) return -1;
    
    return wal_sync_to_lsn(wal, wal_get_current_lsn(wal));
}

// Checkpoint operations
lsn_t wal_create_checkpoint(wal_manager_t* wal, txn_id_t* active_xids, 
                           uint32_t active_count) {
    if (!wal) return INVALID_LSN;
    
    // Create checkpoint data
    uint32_t data_size = sizeof(wal_checkpoint_data_t) + 
                        active_count * sizeof(txn_id_t);
    char* checkpoint_data = malloc(data_size);
    if (!checkpoint_data) return INVALID_LSN;
    
    wal_checkpoint_data_t* cp = (wal_checkpoint_data_t*)checkpoint_data;
    cp->checkpoint_lsn = wal_get_current_lsn(wal);
    cp->redo_lsn = wal->flushed_lsn > 0 ? wal->flushed_lsn : BOOTSTRAP_LSN;
    cp->active_txn_count = active_count;
    
    // Copy active transaction IDs
    if (active_count > 0 && active_xids) {
        memcpy(checkpoint_data + sizeof(wal_checkpoint_data_t), 
               active_xids, active_count * sizeof(txn_id_t));
    }
    
    lsn_t checkpoint_lsn = wal_insert_record(wal, WAL_CHECKPOINT, 0, 
                                           checkpoint_data, data_size);
    free(checkpoint_data);
    
    if (checkpoint_lsn != INVALID_LSN) {
        wal->checkpoint_lsn = checkpoint_lsn;
        __atomic_fetch_add(&wal->checkpoints_taken, 1, __ATOMIC_SEQ_CST);
    }
    
    return checkpoint_lsn;
}

// Segment management
wal_segment_t* wal_create_segment(wal_manager_t* wal) {
    if (!wal) return NULL;
    
    wal_segment_t* segment = malloc(sizeof(wal_segment_t));
    if (!segment) return NULL;
    
    memset(segment, 0, sizeof(wal_segment_t));
    
    segment->segment_id = wal->next_segment_id++;
    segment->filename = get_segment_filename(wal->wal_directory, segment->segment_id);
    if (!segment->filename) {
        free(segment);
        return NULL;
    }
    
    // Open segment file
    segment->fd = open(segment->filename, O_CREAT | O_WRONLY | O_APPEND, 0644);
    if (segment->fd < 0) {
        free(segment->filename);
        free(segment);
        return NULL;
    }
    
    segment->start_lsn = wal_get_current_lsn(wal);
    segment->is_active = true;
    
    // Write segment header
    if (write_segment_header(segment) != 0) {
        close(segment->fd);
        unlink(segment->filename);
        free(segment->filename);
        free(segment);
        return NULL;
    }
    
    // Add to segment list
    pthread_rwlock_wrlock(&wal->segments_lock);
    segment->next = wal->segments;
    wal->segments = segment;
    pthread_rwlock_unlock(&wal->segments_lock);
    
    __atomic_fetch_add(&wal->segments_created, 1, __ATOMIC_SEQ_CST);
    
    return segment;
}

int wal_close_segment(wal_manager_t* wal, wal_segment_t* segment) {
    if (!wal || !segment) return -1;
    
    if (segment->fd >= 0) {
        if (segment->needs_sync) {
            fsync(segment->fd);
        }
        close(segment->fd);
        segment->fd = -1;
    }
    
    segment->is_active = false;
    
    free(segment->filename);
    free(segment);
    
    return 0;
}

// Record management
wal_record_t* wal_record_create(wal_record_type_t type, txn_id_t xid,
                               const void* data, uint32_t data_size) {
    wal_record_t* record = malloc(sizeof(wal_record_t));
    if (!record) return NULL;
    
    memset(record, 0, sizeof(wal_record_t));
    
    // Initialize header
    record->header.type = type;
    record->header.length = sizeof(wal_record_header_t) + data_size;
    record->header.xid = xid;
    record->header.prev_lsn = INVALID_LSN;  // Could be linked later
    
    // Copy data if provided
    if (data_size > 0 && data) {
        record->data = malloc(data_size);
        if (!record->data) {
            free(record);
            return NULL;
        }
        memcpy(record->data, data, data_size);
        record->is_allocated = true;
    }
    
    record->data_size = data_size;
    
    return record;
}

void wal_record_destroy(wal_record_t* record) {
    if (!record) return;
    
    if (record->is_allocated && record->data) {
        free(record->data);
    }
    
    free(record);
}

// Buffer management
wal_buffer_t* wal_buffer_create(uint32_t capacity) {
    wal_buffer_t* buffer = malloc(sizeof(wal_buffer_t));
    if (!buffer) return NULL;
    
    memset(buffer, 0, sizeof(wal_buffer_t));
    
    buffer->data = malloc(capacity);
    if (!buffer->data) {
        free(buffer);
        return NULL;
    }
    
    buffer->capacity = capacity;
    
    if (pthread_mutex_init(&buffer->mutex, NULL) != 0 ||
        pthread_cond_init(&buffer->not_full, NULL) != 0 ||
        pthread_cond_init(&buffer->not_empty, NULL) != 0) {
        free(buffer->data);
        free(buffer);
        return NULL;
    }
    
    return buffer;
}

void wal_buffer_destroy(wal_buffer_t* buffer) {
    if (!buffer) return;
    
    pthread_cond_destroy(&buffer->not_empty);
    pthread_cond_destroy(&buffer->not_full);
    pthread_mutex_destroy(&buffer->mutex);
    
    free(buffer->data);
    free(buffer);
}

int wal_buffer_append(wal_buffer_t* buffer, wal_record_t* record) {
    if (!buffer || !record) return -1;
    
    uint32_t record_size = record->header.length;
    
    pthread_mutex_lock(&buffer->mutex);
    
    // Wait for space
    while (buffer->used + record_size > buffer->capacity) {
        pthread_cond_wait(&buffer->not_full, &buffer->mutex);
    }
    
    // Copy record header
    memcpy(buffer->data + buffer->used, &record->header, sizeof(wal_record_header_t));
    buffer->used += sizeof(wal_record_header_t);
    
    // Copy record data
    if (record->data_size > 0) {
        memcpy(buffer->data + buffer->used, record->data, record->data_size);
        buffer->used += record->data_size;
    }
    
    // Signal that buffer has data
    pthread_cond_signal(&buffer->not_empty);
    pthread_mutex_unlock(&buffer->mutex);
    
    return 0;
}

// Utility functions
uint32_t wal_calculate_crc32(const void* data, uint32_t size) {
    return crc32(0L, (const Bytef*)data, size);
}

bool wal_verify_record(wal_record_t* record) {
    if (!record) return false;
    
    // Calculate expected CRC
    uint32_t header_crc = wal_calculate_crc32(&record->header, 
                                            sizeof(wal_record_header_t) - sizeof(uint32_t));
    uint32_t data_crc = record->data_size > 0 ? 
                       wal_calculate_crc32(record->data, record->data_size) : 0;
    uint32_t expected_crc = header_crc ^ data_crc;
    
    return record->header.crc32 == expected_crc;
}

lsn_t wal_get_current_lsn(wal_manager_t* wal) {
    if (!wal) return INVALID_LSN;
    
    pthread_mutex_lock(&wal->lsn_mutex);
    lsn_t lsn = wal->next_lsn - 1;  // Last assigned LSN
    pthread_mutex_unlock(&wal->lsn_mutex);
    
    return lsn;
}

lsn_t wal_get_flushed_lsn(wal_manager_t* wal) {
    if (!wal) return INVALID_LSN;
    return wal->flushed_lsn;
}

void wal_print_stats(wal_manager_t* wal) {
    if (!wal) return;
    
    printf("WAL Manager Statistics:\n");
    printf("  Next LSN: %" PRIu64 "\n", wal->next_lsn);
    printf("  Flushed LSN: %" PRIu64 "\n", wal->flushed_lsn);
    printf("  Checkpoint LSN: %" PRIu64 "\n", wal->checkpoint_lsn);
    printf("  Records written: %" PRIu64 "\n", wal->records_written);
    printf("  Bytes written: %" PRIu64 "\n", wal->bytes_written);
    printf("  Syncs performed: %" PRIu64 "\n", wal->syncs_performed);
    printf("  Checkpoints taken: %" PRIu64 "\n", wal->checkpoints_taken);
    printf("  Segments created: %" PRIu64 "\n", wal->segments_created);
    printf("  Segment size: %u bytes\n", wal->segment_size);
    printf("  Buffer size: %u bytes\n", wal->buffer_size);
    printf("  Sync interval: %u ms\n", wal->sync_interval_ms);
    printf("  Checkpoint interval: %u sec\n", wal->checkpoint_interval_sec);
}

const char* wal_record_type_to_string(wal_record_type_t type) {
    switch (type) {
        case WAL_INVALID: return "INVALID";
        case WAL_INSERT: return "INSERT";
        case WAL_UPDATE: return "UPDATE";
        case WAL_DELETE: return "DELETE";
        case WAL_TRANSACTION_BEGIN: return "TXN_BEGIN";
        case WAL_TRANSACTION_COMMIT: return "TXN_COMMIT";
        case WAL_TRANSACTION_ABORT: return "TXN_ABORT";
        case WAL_CHECKPOINT: return "CHECKPOINT";
        case WAL_PAGE_SPLIT: return "PAGE_SPLIT";
        case WAL_PAGE_MERGE: return "PAGE_MERGE";
        case WAL_CREATE_TABLE: return "CREATE_TABLE";
        case WAL_DROP_TABLE: return "DROP_TABLE";
        case WAL_CREATE_INDEX: return "CREATE_INDEX";
        case WAL_DROP_INDEX: return "DROP_INDEX";
        case WAL_VACUUM: return "VACUUM";
        case WAL_BACKUP_START: return "BACKUP_START";
        case WAL_BACKUP_END: return "BACKUP_END";
        default: return "UNKNOWN";
    }
}

// Background thread implementations
void* wal_writer_thread_func(void* arg) {
    wal_manager_t* wal = (wal_manager_t*)arg;
    
    while (wal->threads_running) {
        pthread_mutex_lock(&wal->buffer->mutex);
        
        // Wait for data or flush request
        while (wal->buffer->used == 0 && !wal->buffer->flush_requested && 
               wal->threads_running) {
            pthread_cond_wait(&wal->buffer->not_empty, &wal->buffer->mutex);
        }
        
        if (!wal->threads_running) {
            pthread_mutex_unlock(&wal->buffer->mutex);
            break;
        }
        
        // Flush buffer if needed
        if (wal->buffer->used > 0 || wal->buffer->flush_requested) {
            wal_buffer_flush(wal, wal->buffer);
        }
        
        pthread_mutex_unlock(&wal->buffer->mutex);
        
        // Sleep for sync interval
        usleep(wal->sync_interval_ms * 1000);
    }
    
    return NULL;
}

void* wal_checkpoint_thread_func(void* arg) {
    wal_manager_t* wal = (wal_manager_t*)arg;
    
    while (wal->threads_running) {
        sleep(wal->checkpoint_interval_sec);
        
        if (!wal->threads_running) break;
        
        // Create checkpoint (simplified - would need active transaction list)
        wal_create_checkpoint(wal, NULL, 0);
    }
    
    return NULL;
}

// Static helper functions
static lsn_t assign_lsn(wal_manager_t* wal) {
    pthread_mutex_lock(&wal->lsn_mutex);
    lsn_t lsn = wal->next_lsn++;
    pthread_mutex_unlock(&wal->lsn_mutex);
    return lsn;
}

static int write_record_to_buffer(wal_manager_t* wal, wal_record_t* record) {
    return wal_buffer_append(wal->buffer, record);
}

static int create_wal_directory(const char* path) {
    struct stat st;
    if (stat(path, &st) == 0) {
        return S_ISDIR(st.st_mode) ? 0 : -1;
    }
    
    return mkdir(path, 0755);
}

static char* get_segment_filename(const char* wal_dir, uint32_t segment_id) {
    int len = strlen(wal_dir) + strlen(WAL_SEGMENT_PREFIX) + 32;
    char* filename = malloc(len);
    if (!filename) return NULL;
    
    snprintf(filename, len, "%s/%s%08u", wal_dir, WAL_SEGMENT_PREFIX, segment_id);
    return filename;
}

static int write_segment_header(wal_segment_t* segment) {
    if (!segment || segment->fd < 0) return -1;
    
    struct {
        uint32_t magic;
        uint32_t version;
        uint32_t segment_id;
        lsn_t start_lsn;
    } header;
    
    header.magic = WAL_MAGIC_NUMBER;
    header.version = WAL_VERSION;
    header.segment_id = segment->segment_id;
    header.start_lsn = segment->start_lsn;
    
    ssize_t written = write(segment->fd, &header, sizeof(header));
    if (written != sizeof(header)) {
        return -1;
    }
    
    segment->size += sizeof(header);
    return 0;
}

static int read_segment_header(wal_segment_t* segment) {
    // Simplified implementation
    return 0;
}

// Placeholder implementations for complex functions
int wal_buffer_flush(wal_manager_t* wal, wal_buffer_t* buffer) {
    if (!wal || !buffer) return -1;
    
    // Write buffer contents to active segment
    if (wal->active_segment && buffer->used > 0) {
        ssize_t written = write(wal->active_segment->fd, buffer->data, buffer->used);
        if (written > 0) {
            wal->active_segment->size += written;
            wal->active_segment->needs_sync = true;
            
            // Update flushed LSN (simplified)
            wal->flushed_lsn = wal->next_lsn - 1;
            
            // Clear buffer
            buffer->used = 0;
            buffer->flush_requested = false;
            
            // Signal waiters
            pthread_cond_broadcast(&wal->flush_cond);
            pthread_cond_signal(&buffer->not_full);
        }
    }
    
    return 0;
}

// Configuration functions
int wal_set_segment_size(wal_manager_t* wal, uint32_t size) {
    if (!wal || size < 1024 * 1024) return -1;  // Minimum 1MB
    wal->segment_size = size;
    return 0;
}

int wal_set_buffer_size(wal_manager_t* wal, uint32_t size) {
    if (!wal || size < 64 * 1024) return -1;  // Minimum 64KB
    wal->buffer_size = size;
    return 0;
}

int wal_set_sync_interval(wal_manager_t* wal, uint32_t interval_ms) {
    if (!wal) return -1;
    wal->sync_interval_ms = interval_ms;
    return 0;
}

int wal_set_checkpoint_interval(wal_manager_t* wal, uint32_t interval_sec) {
    if (!wal) return -1;
    wal->checkpoint_interval_sec = interval_sec;
    return 0;
}

// Simplified placeholder implementations
int wal_restore_checkpoint(wal_manager_t* wal, checkpoint_info_t** checkpoint) {
    if (!wal || !checkpoint) return -1;
    *checkpoint = NULL;
    return 0;
}

int wal_start_recovery(wal_manager_t* wal) {
    if (!wal) return -1;
    wal->in_recovery = true;
    return 0;
}

int wal_get_next_record(wal_manager_t* wal, wal_record_t** record) {
    if (!wal || !record) return -1;
    *record = NULL;
    return 0;
}

int wal_apply_record(wal_manager_t* wal, wal_record_t* record) {
    if (!wal || !record) return -1;
    return 0;
}

int wal_finish_recovery(wal_manager_t* wal) {
    if (!wal) return -1;
    wal->in_recovery = false;
    return 0;
}

int wal_remove_old_segments(wal_manager_t* wal, lsn_t oldest_needed_lsn) {
    if (!wal) return -1;
    // Would remove segments older than oldest_needed_lsn
    return 0;
}

wal_record_t* wal_record_read(wal_manager_t* wal, lsn_t lsn) {
    if (!wal || lsn == INVALID_LSN) return NULL;
    // Would read record with given LSN from segments
    return NULL;
}

int wal_get_segment_count(wal_manager_t* wal) {
    if (!wal) return 0;
    
    int count = 0;
    pthread_rwlock_rdlock(&wal->segments_lock);
    wal_segment_t* segment = wal->segments;
    while (segment) {
        count++;
        segment = segment->next;
    }
    pthread_rwlock_unlock(&wal->segments_lock);
    
    return count;
}

uint64_t wal_get_total_size(wal_manager_t* wal) {
    if (!wal) return 0;
    
    uint64_t total = 0;
    pthread_rwlock_rdlock(&wal->segments_lock);
    wal_segment_t* segment = wal->segments;
    while (segment) {
        total += segment->size;
        segment = segment->next;
    }
    pthread_rwlock_unlock(&wal->segments_lock);
    
    return total;
}